package com.scs.application.modules.dept.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.consts.ErrorCode;
import com.scs.application.core.entity.DataEntity;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.exception.ValidException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.MatrHisDTO;
import com.scs.application.modules.base.entity.*;
import com.scs.application.modules.base.mapper.*;
import com.scs.application.modules.base.service.DeptMapService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.base.util.MatrPassUtil;
import com.scs.application.modules.cfg.utils.ParameterUtils;
import com.scs.application.modules.dept.dto.StockUniQueCode;
import com.scs.application.modules.dept.entity.HisBill;
import com.scs.application.modules.dept.entity.OprtUse;
import com.scs.application.modules.dept.entity.OprtUseItem;
import com.scs.application.modules.dept.mapper.OprtUseItemMapper;
import com.scs.application.modules.dept.mapper.OprtUseMapper;
import com.scs.application.modules.dept.service.HisBillService;
import com.scs.application.modules.dept.service.OprtUseItemService;
import com.scs.application.modules.dept.service.OprtUseService;
import com.scs.application.modules.price.dto.AdjustStockDTO;
import com.scs.application.modules.sys.entity.Flow;
import com.scs.application.modules.sys.entity.FlowButton;
import com.scs.application.modules.sys.entity.Log;
import com.scs.application.modules.sys.entity.User;
import com.scs.application.modules.sys.enums.BusType;
import com.scs.application.modules.sys.enums.LogType;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.sys.service.LogService;
import com.scs.application.modules.sys.service.UserService;
import com.scs.application.modules.thirdparty.dto.*;
import com.scs.application.modules.thirdparty.dto.his.*;
import com.scs.application.modules.thirdparty.service.HisService;
import com.scs.application.modules.thirdparty.service.MscmService;
import com.scs.application.modules.wm.entity.*;
import com.scs.application.modules.wm.enums.LockBusType;
import com.scs.application.modules.wm.enums.UniqueCodeType;
import com.scs.application.modules.wm.enums.WorkOrderType;
import com.scs.application.modules.wm.mapper.StockMapper;
import com.scs.application.modules.wm.mapper.WorkOrderItemMapper;
import com.scs.application.modules.wm.mapper.WorkOrderMapper;
import com.scs.application.modules.wm.service.StockLockLogService;
import com.scs.application.modules.wm.service.StockLockService;
import com.scs.application.modules.wm.service.StockService;
import com.scs.application.modules.wm.service.WorkOrderService;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
public class OprtUseServiceImpl extends BaseServiceImpl<OprtUseMapper, OprtUse> implements OprtUseService {
    @Autowired
    private OprtUseItemService oprtUseItemService;

    @Autowired
    private OprtUseItemMapper oprtUseItemMapper;
    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private MatrMapper matrMapper;
    @Autowired
    private SupplierMapper supplierMapper;
    @Autowired
    private WorkOrderMapper workOrderMapper;
    @Autowired
    private StockService stockService;
    @Autowired
    private WorkOrderItemMapper workOrderItemMapper;
    @Autowired
    private OprtMapper oprtMapper;
    @Autowired
    private PatientMapper patientMapper;
    @Autowired
    private DeptMapper deptMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private HisService hisService;
    @Autowired
    private LogService logService;
    @Autowired
    private HisBillService hisBillService;
    @Autowired
    private UserService userService;
    @Autowired
    private DeptMapService deptMapService;

    @Autowired
    private MscmService mscmService;

    @Autowired
    private MatrPassUtil matrPassUtil;


    @Autowired
    @Lazy
    private StockLockService stockLockService;


    @Autowired
    @Lazy
    private StockLockLogService stockLockLogService;


    @Override
    public boolean saveOrUpdate(OprtUse entity) {
        if (entity.isNewRecord()) {
            entity.setBusKey(serialRuleAdapter.getSerialRuleService(true).generateCode(SerialKeys.DEPT_OPRT_USE_KEY));
        } else {
            List<OprtUseItem> oprtUseItemList = oprtUseItemService.list(Wrappers.<OprtUseItem>query().eq("dept_oprt_use_id", entity.getId()));
            final double[] amountDtl = {0};
            oprtUseItemList.stream().forEach(item -> amountDtl[0] = UtilNum.sum(amountDtl[0], item.getAmount()));
            if (amountDtl[0] != entity.getAmount()) {
                entity.setAmount(amountDtl[0]);
            }
        }
        return super.saveOrUpdate(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        if (!idList.isEmpty()) {
            List<OprtUseItem> oprtUseItems = oprtUseItemService.list(Wrappers.<OprtUseItem>query().in("dept_oprt_use_id", idList));
            List<String> ids = oprtUseItems.stream().map(o -> o.getId()).collect(Collectors.toList());
            oprtUseItemService.removeByIds(ids);
        }
        return super.removeByIds(idList);
    }

    @Override
    protected void beforeHandleFlowChange(FlowContext flowContext, OprtUse entity) {
        super.beforeHandleFlowChange(flowContext, entity);
        String buttonKey = flowContext.getButtonKey();
        OprtUse oprtUseDb = this.getById(entity.getId());
        List<OprtUseItem> oprtUseItemList = oprtUseItemService.list(Wrappers.<OprtUseItem>query().eq("dept_oprt_use_id", flowContext.getBusId()));
        // 提交审核，不允许空明细提交
        if ("submit".equalsIgnoreCase(buttonKey)) {
            Integer count = oprtUseItemService.count(Wrappers.<OprtUseItem>query().eq("dept_oprt_use_id", flowContext.getBusId()));
            if (count == null || count == 0) {
                throw new BusinessException("订单%s请添加明细后提交", oprtUseDb.getBusKey());
            }
            oprtUseItemList.forEach(ob -> {
                //单品数量*单品价格 是否等于 合计金额
                if (UtilNum.mul(ob.getSkuQty(), ob.getSkuPrice()) != ob.getAmount()) {
                    ob.setAmount(UtilNum.mul(ob.getSkuQty(), ob.getSkuPrice()));
                    //单品数量*单品价格 是否等于 合计金额
                    oprtUseItemService.updateById(ob);
                }
            });
        }
        if (flowContext.isEndNode() && oprtUseDb.getFlagUseRedType() != 1) {
            stockService.getExpStockByUC(oprtUseItemList.stream().map(OprtUseItem::getSn).collect(Collectors.toList()));
        }
    }

    @Override
    protected void afterHandleFlowChange(FlowContext flowContext, OprtUse newEntity) {
        super.afterHandleFlowChange(flowContext, newEntity);
        String buttonKey = flowContext.getButtonKey();
        OprtUse entity = flowContext.getBusEntity();

        // 科室审核确认
        if ("review".equalsIgnoreCase(buttonKey)) {
            this.update(Wrappers.<OprtUse>update()
                    .eq("bus_key", entity.getBusKey())
                    .set("flag_dept_audit", 1)
                    .set("dept_audit_modified", new Date()).set("dept_auditodifier", UserUtils.currentUser().getName()));
            List<String> ids = new ArrayList<>();
            ids.add((entity.getId()));
            CommonService.updatebillFlow(ids, LocalDateTime.now(), false);
        }

        boolean endNode = flowContext.isEndNode();
        if (!endNode) {
            return;
        }
        // 如果是结束节点，依据拣货明细创建出库单

        List<OprtUseItem> oprtUseItems = oprtUseItemService.list(Wrappers.<OprtUseItem>query().eq("dept_oprt_use_id", entity.getId()));
        if (oprtUseItems.isEmpty()) {
            throw new BusinessException("病人消耗单没有明细");
        }

        // 生成出库单
        List<WorkOrder> wos = convertUseToOrders(entity, null);

//       过账
        List<String> workIds = wos.stream().map(WorkOrder::getId).collect(Collectors.toList());
        workOrderService.postBatch(workIds);

           /* 暂时注释掉，待后期改造wyt20211208 // 修改记账单，手术，病人字段
            billService.update(Wrappers.<Bill>update()
                .in("ref_id", workIds)
                    .set(StringUtils.isNotBlank(entity.getOprtId()), "oprt_id", entity.getOprtId())
                    .set(StringUtils.isNotBlank(entity.getOprtCode()), "oprt_code", entity.getOprtCode())
                    .set(StringUtils.isNotBlank(entity.getOprtName()), "oprt_name", entity.getOprtName())
                    .set(StringUtils.isNotBlank(entity.getPatientId()), "patient_id", entity.getPatientId())
                    .set(StringUtils.isNotBlank(entity.getPatientNo()), "patient_no", entity.getPatientNo())
                    .set(StringUtils.isNotBlank(entity.getPatientName()), "patient_name", entity.getPatientName())
                    .set("exec_dept_id", entity.getExecDeptId())
                    .set("exec_dept_name", entity.getExecDeptName())
            );

//        修改HIS相关信息
        billMapper.updateItemHis(entity.getId());*/

        if (entity.getFlagUseRedType() == 1) {
            List<String> ids = oprtUseItems.stream().map(s -> s.getStockId()).distinct().collect(Collectors.toList());
            List<Stock> stocksDb = stockService.listStockWithZero(new QueryWrapper<Stock>().in("id", ids), null);
            List<String> matrIds = stocksDb.stream().map(s -> s.getMatrId()).distinct().collect(Collectors.toList());
            List<Matr> matrList = matrMapper.selectList(Wrappers.<Matr>query().in("id", matrIds));

            //价格变动的库存列表
            List<Stock> stockPriceChangeList = stocksDb.stream().filter(stock -> matrList.stream()
                    .filter(matr -> matr.getId().equals(stock.getMatrId())
                            && matr.getSupplierId().equals(stock.getSupplierId())
                            && matr.getFlagOmoc().equals(stock.getFlagOmoc())
                            && !matr.getSkuPrice().equals(stock.getSkuPrice())).count() > 0)
                    .collect(Collectors.toList());
            if (!stockPriceChangeList.isEmpty()) {
                for (Stock stockOld : stockPriceChangeList) {
                    Matr matrNew = matrList.stream().filter(matr -> stockOld.getMatrId().equals(matr.getId())).findFirst().get();
                    AdjustStockDTO adjustStockDTO = new AdjustStockDTO();
                    BeanUtils.copyProperties(stockOld, adjustStockDTO);
                    CommonService.priceChange(matrNew, adjustStockDTO, "MANUAL-BILL-CANCEL", "HIS退费后，一物一码价格变动", true, true, GlobalConsts.adjustTypeHIS);
                }
            }
        }

        flowContext.setHandledMsg(String.format("病人消耗单审核完成，共生成%d个病人消耗出库单", wos.size()));
        log.info("病人消耗单审核完成，共生成{}个病人消耗出库单", wos.size());
        log.info("病人消耗出库单分别为：{}", wos.stream().map(o -> o.getBusKey()).collect(Collectors.joining(",")));
    }

    private List<WorkOrder> convertUseToOrders(OprtUse oprtUse, List<Stock> stockList) {

        List<OprtUseItem> oprtUseItems = oprtUseItemService.list(Wrappers.<OprtUseItem>query().eq("dept_oprt_use_id", oprtUse.getId()));
        //根据库存里面的供应商分组，因为耗材供应商可能被修改
        List<String> stockIdList = oprtUseItems.stream().map(OprtUseItem::getStockId).collect(Collectors.toList());
        if (stockList == null || stockList.size() < 1) {
            if (oprtUse.getFlagUseRedType() == 1) {
                stockList = stockService.listStockWithZero(Wrappers.<Stock>query().in("id", stockIdList), null);
            } else {
                stockList = stockService.list(Wrappers.<Stock>query().in("id", stockIdList));
            }
        }

        if (stockList == null) {
            throw new BusinessException("病人消耗单明细所对应的库存在系统中不存在，转换出库单失败");
        }
        if (stockList.size() != oprtUseItems.size()) {
            throw new BusinessException("病人消耗单明细数量【%s】与库存记录库存数量【%s】不一致，转换出库单失败", oprtUseItems.size(), stockList.size());
        }

        //分组去重，条件：供应商，耗材，寄售，一物一码
        List<Stock> stockGroupList = UtilJava8.stockGroup(stockList);
        ArrayList<WorkOrder> orders = Lists.newArrayList();
        List<Stock> finalStockList = stockList;
        stockGroupList.stream().forEach(stockGroup -> {
            WorkOrderKey orderKey = new WorkOrderKey(stockGroup.getSupplierId(), stockGroup.getFlagConsignment(), stockGroup.getFlagOmoc());

            //符合该分组的所有库存
            List<Stock> stockAddList = UtilJava8.stockFilter(finalStockList, stockGroup);
            WorkOrder order = convertOprtUseItemsToOrder(orderKey, oprtUse, UtilJava8.getWODeptOprtUseItems(stockAddList, oprtUseItems));
            orders.add(order);
        });
        return orders;
    }

    synchronized private WorkOrder convertOprtUseItemsToOrder(WorkOrderKey orderKey,
                                                              OprtUse oprtUse, List<OprtUseItem> oprtUseItems) {

        String supplierId = orderKey.supplierId;
        Supplier supplier = supplierMapper.selectById(supplierId);
        if (supplier == null) {
            log.error("转换出库单失败，消耗单号：{}，供应商 {} 不存在", oprtUse.getBusKey(), supplierId);
            throw new BusinessException("转换科室配送出库单失败,未找到供应商,id=" + supplierId);
        }

        // 出库金额求和
        double sum = oprtUseItems.stream().mapToDouble(o -> o.getAmount()).sum();

        WorkOrder wo = new WorkOrder();

        String name = oprtUse.getCreator();
        if (UserUtils.currentUser() != null) {
            name = UserUtils.currentUser().getName();
        }
        wo.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.OUT_ORDER_KEY))
                .setDirection(GlobalConsts.ORDER_DIRECTION_OUT)
                .setBusDate(new Date()).setBusUser(name)
                .setBusType(WorkOrderType.OPRT_USE)
                .setFlagConsignment(orderKey.consignment).setFlagOmoc(orderKey.omoc)
                .setRefId(oprtUse.getId()).setRefKey(oprtUse.getBusKey()).setRefTable("dept_oprt_use")
                .setSupplierId(supplier.getId()).setSupplierName(supplier.getName())
                .setWarehouseId(oprtUse.getWarehouseId()).setWarehouseName(oprtUse.getWarehouseName())
                .setDeliveryman(name)
                .setAmount(sum)
                .setDeptId(oprtUse.getDeptId()).setDeptName(oprtUse.getDeptName())
                .setRemark(String.format("由消耗单%s转换而来", oprtUse.getBusKey()))
                .setFlowStatus(GlobalConsts.FLOW_END_VALUE)
                .setFlowModified(oprtUse.getFlowModified()).setFlowModifier(oprtUse.getFlowModifier())
        ;
        if (GlobalConsts.YES.equals(oprtUse.getFlagUseRedType())) {
            wo.setDirection(GlobalConsts.ORDER_DIRECTION_IN).setBusType(WorkOrderType.IN_OPRT_RED);
        }
        workOrderMapper.insert(wo);

        for (OprtUseItem oprtUseItem : oprtUseItems) {
            String stockId = oprtUseItem.getStockId();
            Stock stock;
            if (oprtUse.getFlagUseRedType() == 1) {
                stock = stockService.getByIdWithZero(stockId);
            } else {
                stock = stockService.getById(stockId);
            }
            if (stock == null) {
                log.error("库存不存在，SN：{}，RFID：{}，UDI：{}，StockId：{}",
                        oprtUseItem.getSn(), oprtUseItem.getRfid(), oprtUseItem.getUdi(), stockId);
                throw new BusinessException("库存不存在，可能是由于数据错误");
            }
            WorkOrderItem orderItem = new WorkOrderItem();
            String[] ignoreFields = Arrays.asList(DataEntity.class.getDeclaredFields())
                    .stream().map(field -> field.getName()).collect(Collectors.toList()).toArray(new String[]{});
            BeanUtils.copyProperties(stock, orderItem, ignoreFields);
            orderItem.setStockId(stockId).setAmount(oprtUseItem.getAmount()).setPackageQty(oprtUseItem.getPackageQty()).setSkuQty(oprtUseItem.getSkuQty());
            orderItem.setWorkOrderId(wo.getId()).setRemark(String.format("由消耗出库单 %s 转换而来", oprtUse.getBusKey()));
            orderItem.setRefBusItemId(oprtUseItem.getId());
            workOrderItemMapper.insert(orderItem);
        }

        return wo;
    }

    /**
     * 对HIS输入信息进行必要校验
     * @param hisOprtDTOs
     */
    private void validateHisOprtDTO(List<HisOprtDTO> hisOprtDTOs) {
        Optional<HisOprtDTO> optBillFlag = hisOprtDTOs.stream().filter(dto -> dto.getBillFlag() != 1 && dto.getBillFlag() != -1).findFirst();
        if (optBillFlag.isPresent()) {
            throw new BusinessException("仓库【bill_flag】类型【" + optBillFlag.get().getBillFlag() + "】错误，1：计费，-1:退费");
        }

        //科室相关判断
        List<String> hisCodes = Lists.newArrayList();
        List<DeptMap> deptMaps = Lists.newArrayList();
        List<Dept> depts = Lists.newArrayList();
        if (ParameterUtils.isHisOrHrpMap()) {
            hisCodes = hisOprtDTOs.stream().map(HisOprtDTO::getDeptCodeUse).distinct().collect(Collectors.toList());
            hisCodes.addAll(hisOprtDTOs.stream().map(HisOprtDTO::getDeptCodeExec).distinct().collect(Collectors.toList()));
            deptMaps = deptMapService.list(Wrappers.<DeptMap>query().in("his_code", hisCodes));
            if (deptMaps.isEmpty()) {
                throw new BusinessException("消耗科室【" + hisOprtDTOs.get(0).getDeptCodeUse() + "】在系统中未找到，请检查");
            }
            depts = deptMapper.selectList(Wrappers.<Dept>query().in("hrp_code", deptMaps.stream().map(DeptMap::getHrpCode).distinct().collect(Collectors.toList())));

        } else {
            hisCodes = hisOprtDTOs.stream().map(HisOprtDTO::getDeptCodeUse).distinct().collect(Collectors.toList());
            hisCodes.addAll(hisOprtDTOs.stream().map(HisOprtDTO::getDeptCodeExec).distinct().collect(Collectors.toList()));
            depts = deptMapper.selectList(Wrappers.<Dept>query().in("his_code", hisCodes));
        }
        for (HisOprtDTO hisOprtDTO : hisOprtDTOs) {
            Optional<Dept> optDeptUse = depts.stream().filter(dept -> hisOprtDTO.getDeptCodeUse().equals(ParameterUtils.isHisOrHrpMap() ? dept.getHrpCode() : dept.getHisCode())).findFirst();
            if (optDeptUse.isPresent()) {
                hisOprtDTO.setDeptUse(optDeptUse.get());
            } else {
                throw new BusinessException("消耗科室【" + hisOprtDTO.getDeptCodeUse() + "】在系统中未找到，请检查");
            }

            Optional<Dept> optDeptExec = depts.stream().filter(dept -> hisOprtDTO.getDeptCodeExec().equals(ParameterUtils.isHisOrHrpMap() ? dept.getHrpCode() : dept.getHisCode())).findFirst();
            if (optDeptExec.isPresent()) {
                hisOprtDTO.setDeptExec(optDeptExec.get());
            } else {
                throw new BusinessException("执行科室【" + hisOprtDTO.getDeptCodeExec() + "】在系统中未找到，请检查");
            }
            if (ParameterUtils.isHisBillDept()) { //消耗科室==执行科室
                hisOprtDTO.setDeptUse(optDeptExec.get());
            }

            if (StringUtils.isBlank(hisOprtDTO.getDeptUse().getWarehouseId()) || StringUtils.isBlank(hisOprtDTO.getDeptUse().getWarehouseName())) {
                throw new BusinessException("消耗科室【" + hisOprtDTO.getDeptUse().getName() + "】未设置有效仓库，请联系运营人员进行设置");
            }
        }

        List<String> oprtCodes = hisOprtDTOs.stream().map(HisOprtDTO::getOprtCode).distinct().collect(Collectors.toList());
        if (!oprtCodes.isEmpty()) {
            List<Oprt> oprts = oprtMapper.selectList(Wrappers.<Oprt>query().in("code", oprtCodes));
            if (!oprts.isEmpty()) {
                for (HisOprtDTO hisOprtDTO : hisOprtDTOs) {
                    if (StringUtils.isBlank(hisOprtDTO.getOprtCode())) {
                        continue;
                    }
                    oprts.stream().filter(oprt -> hisOprtDTO.getOprtCode().equals(oprt.getCode()))
                            .findFirst().ifPresent(oprt -> hisOprtDTO.setOprt(oprt));
                }
            }
        }
        hisOprtDTOs.stream().filter(hisOprtDTO -> hisOprtDTO.getOprt() == null).forEach(hisOprtDTO -> {
            hisOprtDTO.setOprt(new Oprt());
            hisOprtDTO.getOprt().setCode(hisOprtDTO.getOprtCode()).setDeptId(hisOprtDTO.getDeptUse().getId());
        });

        // 患者
        List<String> patientNos = hisOprtDTOs.stream().map(HisOprtDTO::getPatientNo).distinct().collect(Collectors.toList());
        List<String> inpatientNos = hisOprtDTOs.stream().map(HisOprtDTO::getInpatientNo).distinct().collect(Collectors.toList());
        List<String> outpatientNos = hisOprtDTOs.stream().map(HisOprtDTO::getOutpatientNo).distinct().collect(Collectors.toList());
        if (!patientNos.isEmpty() || !inpatientNos.isEmpty() && !outpatientNos.isEmpty()) {
            List<Patient> patients = patientMapper.selectList(Wrappers.<Patient>query()
                    .in(!patientNos.isEmpty(), "no", patientNos).or()
                    .in(!inpatientNos.isEmpty(), "inpatient_no", inpatientNos).or()
                    .in(!outpatientNos.isEmpty(), "outpatient_no", outpatientNos));
            if (!patients.isEmpty()) {
                for (HisOprtDTO hisOprtDTO : hisOprtDTOs) {
                    if (StringUtils.isNotBlank(hisOprtDTO.getPatientNo())) {
                        patients.stream().filter(patient -> hisOprtDTO.getPatientNo().equals(patient.getNo())).findFirst()
                                .ifPresent(patient -> hisOprtDTO.setPatient(patient));
                    }
                    //根据门诊号
                    if (hisOprtDTO.getPatient() == null && StringUtils.isNotBlank(hisOprtDTO.getInpatientNo())) {
                        patients.stream().filter(patient -> hisOprtDTO.getInpatientNo().equals(patient.getInpatientNo())).findFirst()
                                .ifPresent(patient -> hisOprtDTO.setPatient(patient));
                    }
                    if (hisOprtDTO.getPatient() == null && StringUtils.isNotBlank(hisOprtDTO.getOutpatientNo())) {
                        patients.stream().filter(patient -> hisOprtDTO.getOutpatientNo().equals(patient.getOutpatientNo())).findFirst()
                                .ifPresent(patient -> hisOprtDTO.setPatient(patient));
                    }
                    if (hisOprtDTO.getPatient() == null) {
                        hisOprtDTO.setPatient(new Patient());
                        hisOprtDTO.getPatient().setNo(hisOprtDTO.getPatientNo()).setId("0");
                    }
                }
            }
        }
        hisOprtDTOs.stream().filter(hisOprtDTO -> hisOprtDTO.getPatient() == null).forEach(hisOprtDTO -> {
            hisOprtDTO.setPatient(new Patient());
            hisOprtDTO.getPatient().setNo(hisOprtDTO.getPatientNo()).setId("0");
        });
    }

    /**
     * 对HIS输入库存进行必要校验
     * @param stockUniQueCodes
     */
    private void validateHisOprtStock(List<StockUniQueCode> stockUniQueCodes, List<String> ucList) {
        if (stockUniQueCodes.size() == 0) {
            throw new BusinessException("该唯一码【%s】未找到相关库存记录，请检查", ucList.get(0));
        }
        List<StockUniQueCode> duplicates = stockUniQueCodes.stream().filter(ob1 -> ucList.indexOf(ob1.getSn()) != -1 && ucList.indexOf(ob1.getRfid()) != -1).collect(Collectors.toList());
        if (duplicates != null && duplicates.size() > 0) {
            throw new BusinessException("该耗材即扫描了RFID【%s】又扫描了SN【%s】，请检查", duplicates.get(0).getRfid(), duplicates.get(0).getSn());
        }
        //是否有库存记录，不管退费或者计费
        for(String uc : ucList) {
            if (!stockUniQueCodes.stream().filter(ob1 -> uc.equals(ob1.getSn()) || uc.equals(ob1.getRfid())).findFirst().isPresent()) {
                throw new BusinessException("该唯一码【%s】未找到相关库存记录，请检查", uc);
            }
        }
    }

    private void hisAfterFlow(OprtUse oprtUse) {
        //审核通过
        FlowContext flowContext1 = new FlowContext();
        FlowButton flowButton1 = new FlowButton();
        Flow flow1 = new Flow();
        flowButton1.setFlagEnd(true).setCode("end");
        flowContext1.setButton(flowButton1);
        flowContext1.setBusEntity(oprtUse);
        flow1.setName("审核通过");
        flowContext1.setFlow(flow1);
        flowContext1.setBusId(oprtUse.getId());
        afterHandleFlowChange(flowContext1, oprtUse);
    }

    /**
     * 保存HIS消耗信息
     * @param hisOprtUse
     */
    private List<OprtUse> hisUseSave(HisOprtDTO hisOprtUse) {
        User user = userService.findByWorkNo(UtilCommon.getStr(hisOprtUse.getUser(), "his"));
        String userName = "his";
        if (user != null) {
            userName = user.getName();
        }

        List<OprtUse> oprtUseList = Lists.newArrayList();
        List<Stock> stockList = stockMapper.selectList(Wrappers.<Stock>query().in("sn", hisOprtUse.getUcList()).or().in("rfid", hisOprtUse.getUcList()));
        if (stockList.size() != hisOprtUse.getUcList().size()) {
            List<StockUniQueCode> stockUniQueCodes = stockList.stream().map(stock -> {
                StockUniQueCode stockUniQueCode = new StockUniQueCode();
                stockUniQueCode.setSn(stock.getSn()).setRfid(stock.getRfid());
                return stockUniQueCode;
            }).collect(Collectors.toList());
            validateHisOprtStock(stockUniQueCodes, hisOprtUse.getUcList());
        }
        //消耗仓库为实物所对应的科室仓库
        Map<String, List<Stock>> stockMap = stockList.stream().collect(
                Collectors.groupingBy(o -> o.getWarehouseId()));

        for (String s : stockMap.keySet()) {
            List<Stock> stocks = stockMap.get(s);
            //是否禁用耗材校验--计费耗材禁用校验
            matrPassUtil.ckeckMatrPass("charging", stocks.stream().map(Stock::getMatrId).collect(Collectors.toList()));
            Stock stockWarehouse = stocks.get(0);
            //主表
            OprtUse oprtUse = new OprtUse();
            oprtUse.setBusType("HIS").setFlagUseRedType(GlobalConsts.YES.equals(hisOprtUse.getBillFlag()) ? GlobalConsts.NO : GlobalConsts.YES)
                    .setOprtDate(hisOprtUse.getOprt().getDate()).setOprtCode(hisOprtUse.getOprtCode()).setBusDate(hisOprtUse.getBusDate())
                    .setOprtId(hisOprtUse.getOprt().getId()).setOprtName(hisOprtUse.getOprt().getName()).setPatientId(hisOprtUse.getPatient().getId())
                    .setInpatientNo(hisOprtUse.getPatient().getInpatientNo()).setOutpatientNo(hisOprtUse.getOutpatientNo())
                    .setPatientNo(hisOprtUse.getPatient().getNo()).setPatientAge(hisOprtUse.getPatient().getAge()).setPatientName(hisOprtUse.getPatient().getName())
                    .setPatientId(hisOprtUse.getPatient().getId())
                    .setBedNo(hisOprtUse.getPatient().getBedNo()).setDocNameSug(hisOprtUse.getOprt().getDoctorNameSug())
                    .setDocNameApply(hisOprtUse.getOprt().getDoctorNameApply()).setDeptId(hisOprtUse.getDeptUse().getId())
                    .setExecDeptId(hisOprtUse.getDeptExec().getId()).setExecDeptName(hisOprtUse.getDeptExec().getName())
                    .setDeptName(hisOprtUse.getDeptUse().getName()).setRefKey(hisOprtUse.getRefkey())
                    .setAmount(0d)
                    .setWarehouseId(stockWarehouse.getWarehouseId()).setWarehouseName(stockWarehouse.getWarehouseName())
                    .setFlowStatus("end").setFlowModifier(userName).setFlowModified(LocalDateTime.now())
                    .setCreator(hisOprtUse.getUser());

            if (StringUtils.isNotBlank(hisOprtUse.getOprtCode())) {
                oprtUse.setOprtCode(hisOprtUse.getOprtCode());
            }
            if (ObjectUtil.isNotNull(hisOprtUse.getOprtDate())) {
                oprtUse.setOprtDate(hisOprtUse.getOprtDate());
            }
            if (ObjectUtil.isNotNull(hisOprtUse.getOprtName())) {
                oprtUse.setOprtName(hisOprtUse.getOprtName());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getPatientName())) {
                oprtUse.setPatientName(hisOprtUse.getPatientName());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getBedNo())) {
                oprtUse.setBedNo(hisOprtUse.getBedNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getDocNameSug())) {
                oprtUse.setDocNameSug(hisOprtUse.getDocNameSug());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getDocNameApply())) {
                oprtUse.setDocNameApply(hisOprtUse.getDocNameApply());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getInpatientNo())) {
                oprtUse.setInpatientNo(hisOprtUse.getInpatientNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getPatientNo())) {
                oprtUse.setPatientNo(hisOprtUse.getPatientNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getOutpatientNo())) {
                oprtUse.setOutpatientNo(hisOprtUse.getOutpatientNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getOutpatientNo())) {
                oprtUse.setOutpatientNo(hisOprtUse.getOutpatientNo());
            }
           // 保存主表
            this.saveOrUpdate(oprtUse);
            //保存明细
            oprtUseItemService.saveByStockIds(stocks.stream().map(Stock::getId).collect(Collectors.toList()), oprtUse.getId());
            hisAfterFlow(oprtUse);
            oprtUseList.add(oprtUse);
        }
        return oprtUseList;
    }

    /**
     * 保存HIS冲红信息
     * @param hisOprtUse
     */
    private List<OprtUse> hisRedSave(HisOprtDTO hisOprtUse) {
        User user = userService.findByWorkNo(UtilCommon.getStr(hisOprtUse.getUser(), "his"));
        String userName = "his";
        if (user != null) {
            userName = user.getName();
        }

        List<OprtUse> oprtUseList = Lists.newArrayList();
        List<OprtUseItem> oprtUseItemList = oprtUseItemMapper.getRedItemsBySn(hisOprtUse.getDeptUse().getId(), hisOprtUse.getUcList());
        if (oprtUseItemList.size() != hisOprtUse.getUcList().size()) {
            List<StockUniQueCode> stockUniQueCodes = oprtUseItemList.stream().map(stock -> {
                StockUniQueCode stockUniQueCode = new StockUniQueCode();
                stockUniQueCode.setSn(stock.getSn()).setRfid(stock.getRfid());
                return stockUniQueCode;
            }).collect(Collectors.toList());
            validateHisOprtStock(stockUniQueCodes, hisOprtUse.getUcList());
        }

        Map<String, List<OprtUseItem>> useItemMap = oprtUseItemList.stream().collect(
                Collectors.groupingBy(o -> o.getWarehouseId()));

        for (String s : useItemMap.keySet()) {
            List<OprtUseItem> useItems = useItemMap.get(s);
            OprtUse oprtUse = this.getById(useItems.get(0).getDeptOprtUseId());
            if (oprtUse == null) {
                throw new BusinessException("该唯一码【%s】未找到相关消耗记录，请检查", useItems.get(0).getSn());
            }
            OprtUse oprtUseRed = new OprtUse();
            BeanUtils.copyProperties(oprtUse, oprtUseRed, "id");
            oprtUseRed.setFlagUseRedType(GlobalConsts.YES)
                    .setBusDate(hisOprtUse.getBusDate())
                    .setRefKey(hisOprtUse.getRefkey())
                    .setAmount(0d)
                    .setFlowStatus("end").setFlowModifier(userName).setFlowModified(LocalDateTime.now())
                    .setCreator(hisOprtUse.getUser());

            if (StringUtils.isNotBlank(hisOprtUse.getOprtCode())) {
                oprtUseRed.setOprtCode(hisOprtUse.getOprtCode());
            }
            if (ObjectUtil.isNotNull(hisOprtUse.getOprtDate())) {
                oprtUseRed.setOprtDate(hisOprtUse.getOprtDate());
            }
            if (ObjectUtil.isNotNull(hisOprtUse.getOprtName())) {
                oprtUseRed.setOprtName(hisOprtUse.getOprtName());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getPatientName())) {
                oprtUseRed.setPatientName(hisOprtUse.getPatientName());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getBedNo())) {
                oprtUseRed.setBedNo(hisOprtUse.getBedNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getDocNameSug())) {
                oprtUseRed.setDocNameSug(hisOprtUse.getDocNameSug());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getDocNameApply())) {
                oprtUseRed.setDocNameApply(hisOprtUse.getDocNameApply());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getInpatientNo())) {
                oprtUseRed.setInpatientNo(hisOprtUse.getInpatientNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getPatientNo())) {
                oprtUseRed.setPatientNo(hisOprtUse.getPatientNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getOutpatientNo())) {
                oprtUseRed.setOutpatientNo(hisOprtUse.getOutpatientNo());
            }
            if (StringUtils.isNotBlank(hisOprtUse.getOutpatientNo())) {
                oprtUseRed.setOutpatientNo(hisOprtUse.getOutpatientNo());
            }

            // 保存主表
            this.saveOrUpdate(oprtUseRed);
            //保存明细
            oprtUseItemService.useRedByHisUseItems(useItems, oprtUseRed.getId());
            hisAfterFlow(oprtUseRed);
            oprtUseList.add(oprtUseRed);
        }
        return oprtUseList;
    }

    /**
     * @Description： HIS计费或者退费
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<OprtUse> hisSaveOprtUse(HisOprtUse hisOprtUse) {
        List<HisOprtUse.HisOprtUserDtl> hisDtls = hisOprtUse.getDtls();
        if (hisDtls.isEmpty()) {
            throw new BusinessException("消耗明细不能为空");
        }

        List<String> ucList = hisDtls.stream().map(o -> o.getUniqueCode()).distinct().collect(Collectors.toList());
        if (ucList.size() < hisDtls.size()) {
            throw new BusinessException("消耗明细中存在重复的唯一码，请检查");
        }
        hisOprtUse.setUcList(ucList);

        //校验数据
        List<HisOprtDTO> hisOprtUses = Lists.newArrayListWithCapacity(1);
        hisOprtUses.add(hisOprtUse);
        validateHisOprtDTO(hisOprtUses);

        if (hisOprtUse.getBillFlag() == 1) { //消耗
            return hisUseSave(hisOprtUse);
        } else { //冲红
            return hisRedSave(hisOprtUse);
        }
    }

    /**
     * @Description： HIS计费或者退费
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void hisSaveOprtUseBatch(List<HisOprtUseBatch> hisOprtUseBatches) {
        if (hisOprtUseBatches == null || hisOprtUseBatches.size() == 0) {
            throw new BusinessException("病人计费单不能为空");
        }
        //是否重复
        List<String> ucList = hisOprtUseBatches.stream().map(o -> o.getUniqueCode()).distinct().collect(Collectors.toList());
        if (ucList.size() < hisOprtUseBatches.size()) {
            throw new BusinessException("消耗明细中存在重复的唯一码，请检查");
        }

        List<HisOprtDTO> hisOprtDTOS = Lists.newArrayListWithCapacity(hisOprtUseBatches.size());
        hisOprtUseBatches.stream().forEach(hisOprtUseBatch -> hisOprtDTOS.add(hisOprtUseBatch));
        validateHisOprtDTO(hisOprtDTOS);

        List<HisOprtUseBatch> hisUseList = hisOprtUseBatches.stream().filter(oprt -> oprt.getBillFlag() == 1).collect(Collectors.toList());
        List<HisOprtUseBatch> hisRedList = hisOprtUseBatches.stream().filter(oprt -> oprt.getBillFlag() == -1).collect(Collectors.toList());
        List<OprtUse> oprtUseList = Lists.newArrayList();
        if (!hisUseList.isEmpty()) {
           Map<String, List<HisOprtUseBatch>> mapHisUse = hisUseList.stream().collect(Collectors.groupingBy(hisUse -> hisUse.getOprt().getCode() + hisUse.getDeptUse().getId())); //根据手术单号和科室来分组
            for(Map.Entry<String, List<HisOprtUseBatch>> entry : mapHisUse.entrySet()) {
                List<HisOprtUseBatch> hisOprtUseBatchesList = entry.getValue();
                HisOprtUseBatch hisOprtUseBatch = hisOprtUseBatchesList.get(0);
                hisOprtUseBatch.setUcList(hisOprtUseBatchesList.stream().map(HisOprtUseBatch::getUniqueCode).collect(Collectors.toList()));
                oprtUseList.addAll(hisUseSave(hisOprtUseBatch));
            }
        }
        if (!hisRedList.isEmpty()) {
            Map<String, List<HisOprtUseBatch>> mapHisRed = hisRedList.stream().collect(Collectors.groupingBy(hisUse -> hisUse.getOprt().getCode() + hisUse.getDeptUse().getId())); //根据手术单号和科室来分组
            for (Map.Entry<String, List<HisOprtUseBatch>> entry : mapHisRed.entrySet()) {
                List<HisOprtUseBatch> hisOprtUseBatchesList = entry.getValue();
                HisOprtUseBatch hisOprtUseBatch = hisOprtUseBatchesList.get(0);
                hisOprtUseBatch.setUcList(hisOprtUseBatchesList.stream().map(HisOprtUseBatch::getUniqueCode).collect(Collectors.toList()));
                oprtUseList.addAll(hisRedSave(hisOprtUseBatch));
            }
        }
    }


    @Override
    public void docInfoSave() {
        long starTime = System.currentTimeMillis();
        JSONObject logdesc = new JSONObject();
        Log log = Log.getLog(BusType.HisType.type08, LogType.success, "system", logdesc);
        try {
            hisService.syncHisPatient();
            hisService.syncHisOprt();
            List<OprtUse> oprtUses = this.list(new QueryWrapper<OprtUse>().eq("IFNULL(oprt_id,0)", 0).or().eq("IFNULL(patient_id,0)", 0));
            List<OprtUse> updateList = new ArrayList<>(oprtUses.size());
            for (OprtUse oprtUse : oprtUses) {
                List<HisBill> hisBills = hisBillService.list(new QueryWrapper<HisBill>().eq("his_key", oprtUse.getRefKey()));
                if (hisBills.isEmpty()) {
                    continue;
                }
                HisBill hisBill = hisBills.get(0);
                List<Patient> inPatients = patientMapper.selectList(new QueryWrapper<Patient>().eq("no", hisBill.getPatientCode()));
                if (inPatients.isEmpty()) {
                    continue;
                }
                Patient patient = inPatients.get(0);
                oprtUse.setPatientId(patient.getId())
                        .setPatientAge(patient.getAge())
                        .setInpatientNo(patient.getInpatientNo())
                        .setPatientName(patient.getName()).setBedNo(patient.getBedNo()).setPatientNo(patient.getNo());
                List<Oprt> oprts = oprtMapper.selectList(new QueryWrapper<Oprt>().eq("code", hisBill.getOprtCode()));
                if (!oprts.isEmpty()) {
                    Oprt oprt = oprts.get(0);
                    oprtUse.setOprtDate(oprt.getDate())
                            .setOprtName(oprt.getName())
                            .setDocNameApply(oprt.getDoctorNameApply())
                            .setDocNameSug(oprt.getDoctorNameSug())
                            .setOprtId(oprt.getId());
                }

                updateList.add(oprtUse);
            }
            if (!updateList.isEmpty()) {
                this.updateBatchById(updateList);
                /*暂时注释掉，待后期改造wyt20211208 updateList.forEach(oprtUse -> {
                    billMapper.billPatient(oprtUse.getId());
                });*/
            }
        } catch (Exception e) {
            log.setLog(LogType.error, e.getMessage());
        } finally {
            long endTime = System.currentTimeMillis(); //获取结束时间
            String ms = DateUtils.formatTime(endTime - starTime);
            log.setMsg("执行时间" + ms);
            logService.save(log);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public OprtUse updateInfo(String busKey) {
        OprtUse oprtUse = this.getOne((new QueryWrapper<OprtUse>().eq("bus_key", busKey)));
        if (StringUtils.isNotBlank(oprtUse.getRefKey())) {
            List<HisBillDtl> hisBillDtl = hisService.getHisBillDtl(oprtUse.getRefKey());
            if (!hisBillDtl.isEmpty()) {
                HisBillDtl billDtl = hisBillDtl.get(0);
                Dept deptExe = deptMapper.selectOne((new QueryWrapper<Dept>().eq("his_code", billDtl.getDept_code_op())));
                Dept deptPatient = deptMapper.selectOne((new QueryWrapper<Dept>().eq("his_code", billDtl.getDept_code_patient())));
                oprtUse.setDeptId(deptPatient.getId()).setDeptName(deptPatient.getName())
                        .setExecDeptId(deptExe.getId()).setExecDeptName(deptExe.getName());
                this.updateCascadeById(oprtUse);

                workOrderMapper.updateOrderDept(busKey);
//  暂时注释掉，待后期改造wyt20211208              billMapper.updateOrderDept(busKey);
            }
        }
        return oprtUse;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public RestResult toRedById(String oprtUseId) {
        OprtUse oprtUse = this.getById(oprtUseId);
        if (oprtUse == null) {
            throw new BusinessException("单据不存在或者已被删除");
        }

        //首先判断该消耗单是否可以被冲红
        QueryWrapper<OprtUseItem> itemQueryWrapper  = Wrappers.<OprtUseItem>query().eq("dept_oprt_use_id", oprtUseId);
        List<OprtUseItem> oprtUseItems = oprtUseItemService.listForRedList(itemQueryWrapper);
        if (oprtUseItems == null || oprtUseItems.isEmpty()) {
            throw new BusinessException("该消耗单下没有明细或者明细都已经被冲红！");
        }
        //oprtUseItems = oprtUseItems.stream().filter(item -> oprtUseId.equals(item.getDeptOprtUseId())).collect(Collectors.toList());
        if (oprtUseItems == null || oprtUseItems.isEmpty()) {
            throw new BusinessException("该消耗单下没有明细或者明细都已经被冲红！");
        }
        OprtUse oprtUseRed = new OprtUse();
        BeanUtils.copyProperties(oprtUse, oprtUseRed);
        oprtUseRed.setFlagUseRedType(1).setBusType("MANUAL")
                .setBusDate(new Date()).setFlowStatus("start").setFlowModifier(UserUtils.currentUser().getName()).setFlowModified(LocalDateTime.now())
                .setCreator(UserUtils.currentUser().getName()).setGmtCreate(LocalDateTime.now()).setModifier(null).setGmtModified(null).setId(null);
        oprtUseRed.setAmount(oprtUseItems.stream().mapToDouble(OprtUseItem::getAmount).sum());
        oprtUseRed.setBusKey(serialRuleAdapter.getSerialRuleService(true).generateCode(SerialKeys.DEPT_OPRT_USE_KEY));
        this.save(oprtUseRed);

        List<OprtUseItem> redOprtUseItems = new ArrayList<OprtUseItem>();
        oprtUseItems.forEach(oprtUseItem -> {
            OprtUseItem redOprtUseItem = new OprtUseItem();
            BeanUtils.copyProperties(oprtUseItem, redOprtUseItem);
            redOprtUseItem.setDeptOprtUseId(oprtUseRed.getId()).setRemark("病人消耗单冲红").setBillId(null).setBillItemId(null).setId(null)
            .setGmtModified(LocalDateTime.now()).setGmtCreate(LocalDateTime.now())
            .setCreator(UserUtils.currentUser().getName()).setModifier(null);
            redOprtUseItems.add(redOprtUseItem);
        });
        oprtUseItemService.saveBatch(redOprtUseItems);

        return RestResult.ok("冲红成功", oprtUseRed);
    }

    /**
     * 订单标识，用来作为转换订单时的标识
     */
    @EqualsAndHashCode
    @AllArgsConstructor
    private class WorkOrderKey {
        private String supplierId;
        private boolean consignment;
        private boolean omoc;
    }

    /**
     * 同步病人消耗单至供应商平台
     *
     * @return
     */
    @Override
    public String syncToMSCM() {
        // 只推送已审核、未推送的
        List<OprtUse> oprtUses = list(Wrappers.<OprtUse>query()
                .eq("flag_pushed", false)
                .eq("flow_status", "end")
        );
        if (oprtUses.isEmpty()) {
            return "没有需要推送的计费数据";
        }
        List<String> idListAll = oprtUses.stream().map(OprtUse::getId).collect(Collectors.toList());

        List<DeptOprtUseDTO> dtos = buildMscmOprtUser(oprtUses,idListAll);
        List<OprtUseItem> items = oprtUseItemService.list(Wrappers.<OprtUseItem>query().in("dept_oprt_use_id", idListAll));
        List<String> spIdList = items.stream().map(o -> o.getSupplierId()).distinct().collect(Collectors.toList());
        List<Supplier> suppliers = supplierMapper.selectList(Wrappers.<Supplier>query().in("id", spIdList).isNull("mscm_code"));
        String msgAppend="";
        if (suppliers != null && suppliers.size() > 0) {
            msgAppend = ",以下供应商尚未同步，无法推送,\n "+CollectionUtil.join(suppliers.stream().map(Supplier::getName).collect(Collectors.toList()), ",");
        }

        List<List<DeptOprtUseDTO>> listPush = null;
        if (dtos.size() <= 20) {
            listPush = new ArrayList<>();
            listPush.add(dtos);
        } else {
            listPush = Lists.partition(dtos, new Double((Math.ceil(dtos.size() / 20))).intValue());
        }
        int successNum = 0;
        log.info("syncToMSCM 需推送数量{}",listPush.size());
        int num= 1;
        for(List<DeptOprtUseDTO> listEach : listPush) {
            try {
                List<String> idListPush = listEach.stream().map(o -> o.getMainId()).collect(Collectors.toList());
                mscmService.pushDeptOprtUses(listEach);
                update(Wrappers.<OprtUse>update()
                        .in("id", idListPush)
                        .set("flag_pushed", true)
                        .set("gmt_pushed", new Date())
                );
                successNum+=idListPush.size();
            }catch (Exception e) {
                log.error("syncToMSCM 第{}批数据推送异常",num,e);
                msgAppend+=StrUtil.format("syncToMSCM 第{}批数据推送异常,原因:{} \n",num,e.getMessage());
            }
            num++;
        }

        if (msgAppend.length() > 0) {
            msgAppend ="异常信息如下\n" + msgAppend;
        }

        return StrUtil.format("推送计费数据(主单据)，需推送{}，成功{}，失败{}\n {}",dtos.size() ,successNum,dtos.size() -successNum,  msgAppend);
    }

    /**
     * 生成供应商推送信息
     *
     * @param dtos
     */
    private List<DeptOprtUseDTO> buildMscmOprtUser(List<OprtUse> dtos,List<String> idListAll) {
        List<DeptOprtUseDTO> oprtUseList = Lists.newArrayList();

        List<OprtUseItem> itemsAll = oprtUseItemService.list(Wrappers.<OprtUseItem>query().in("dept_oprt_use_id", idListAll));
        List<Supplier> suppliers = supplierMapper.selectBatchIds(itemsAll.stream().map(o -> o.getSupplierId()).collect(Collectors.toSet()));
        Map<String, Supplier> supplierMap = suppliers.stream().collect(Collectors.toMap(o -> o.getId(), o -> o));

        List<OprtUseItem> itemsOne;
        for (OprtUse oprtUse : dtos) {
            DeptOprtUseDTO dto = new DeptOprtUseDTO();
            BeanUtils.copyProperties(oprtUse, dto);
            dto.setMainId(oprtUse.getId());
            itemsOne = itemsAll.stream().filter(tmp -> tmp.getDeptOprtUseId().equals(oprtUse.getId())).collect(Collectors.toList());

            AtomicBoolean isIgnore = new AtomicBoolean(false);
            itemsOne.stream().filter(tmp -> supplierMap.get(tmp.getSupplierId()) == null || StringUtils.isBlank(supplierMap.get(tmp.getSupplierId()).getMscmCode()))
                    .findFirst().ifPresent(tmp -> {
                isIgnore.set(true);
            });
            if (isIgnore.get()) {
                continue;
            }

            List<DeptOprtUseDTO.DeptOprtUseItemDTO> rawItems = Lists.newArrayListWithExpectedSize(itemsOne.size());
            isIgnore.set(false);
            for (OprtUseItem item : itemsOne) {
                Supplier supplier = supplierMap.get(item.getSupplierId());
                if (supplier == null || StringUtils.isBlank(supplier.getMscmCode())) {
                    isIgnore.set(true);
                    continue;
                }
                //供应商平台对应供应商ID set 到item
                item.setSupplierId(supplier.getMscmCode());
                DeptOprtUseDTO.DeptOprtUseItemDTO itemDTO = new DeptOprtUseDTO.DeptOprtUseItemDTO();
                BeanUtils.copyProperties(item, itemDTO);
                itemDTO.setDtlId(item.getId());
                rawItems.add(itemDTO);
            }
            dto.setItems(rawItems);
            if (isIgnore.get()) {
                continue;
            }
            oprtUseList.add(dto);
        }
        return oprtUseList;
    }

    @Override
    public IPage pageForSelect(QueryContext context, Map<String, Object> userParam) {
        return this.baseMapper.pageForSelect(context.getPage(), context.getWrapper(), context.getParams(), userParam);

    }

    /**
     * 科室审核数据更新
     *
     * @param idList
     * @return
     */
    @Override
    public void auditDeptOprtUse(List<String> idList) {
        // 审核数据取得
        List<OprtUse> oprtUses = list(Wrappers.<OprtUse>query()
                .in("id", idList)
                .eq("flag_dept_audit", 0)
                .in("flow_status", "end", "confirm")
        );

        if (oprtUses.isEmpty()) {
            throw new BusinessException("该单据已审核，请检查！");
        }

        this.update(Wrappers.<OprtUse>update()
                .in("id", oprtUses.stream().map(o -> o.getId()).collect(Collectors.toList()))
                .set("flag_dept_audit", 1)
                .set("dept_audit_modified", new Date()).set("dept_auditodifier", UserUtils.currentUser().getName()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResult substituteOprtUse() {
        List<HisBill> hisBills = hisBillService.list(new QueryWrapper<HisBill>().eq("flag_comparison", 0).orderByAsc("bill_date"));
        RestResult restResult = RestResult.ok("成功");
        Log log = Log.getLog(BusType.HisType.type13, LogType.success, "system", "");
        try {
            for (HisBill hisBill : hisBills) {
                Integer flagUseRedType = hisBill.getQty() > 0 ? 0 : 1;
                Stock stockHis = stockService.getStockByUniqueCode(hisBill.getSn());
                OprtUse oprtUseBill = this.baseMapper.getOprtUse(stockHis.getRfid(), hisBill.getHisKey(), flagUseRedType, hisBill.getPatientCode());
                if (oprtUseBill != null) {
                    hisBill.setFlagComparison(true);
                    hisBillService.updateCascadeById(hisBill);
                    continue;
                }
                // 手术单
                Oprt oprt = oprtMapper.selectOne(new QueryWrapper<Oprt>()
                        .eq("code", hisBill.getOprtCode()));

                if (oprt == null) {
                    oprt = new Oprt();
                    oprt.setCode("").setDeptId("0");
                }
                // 患者
                Patient patient = null;
                //根据病案号
                patient = patientMapper.selectOne(new QueryWrapper<Patient>()
                        .eq("no", hisBill.getPatientCode()));

                Dept deptUse = null;
                Dept deptExec = null;

                //                以HRP还是HIS为准
                if (ParameterUtils.isHisOrHrpMap()) {
                    DeptMap useMap = deptMapService.getOne(Wrappers.<DeptMap>query().eq("his_code", hisBill.getDeptCodePatient()));
                    if (useMap == null) {
                        throw new BusinessException("消耗科室【" + hisBill.getDeptCodePatient() + "】对应关系在系统中未找到，请检查");
                    }
                    deptUse = deptMapper.selectOne(Wrappers.<Dept>query().eq("hrp_code", useMap.getHrpCode()));
                    if (deptUse == null) {
                        throw new BusinessException("消耗科室【" + hisBill.getDeptCodePatient() + "】在系统中未找到，请检查");
                    }
                    DeptMap execMap = deptMapService.getOne(Wrappers.<DeptMap>query().eq("his_code", hisBill.getDeptCodeOp()));
                    if (execMap == null) {
                        throw new BusinessException("消耗科室【" + hisBill.getDeptCodeOp() + "】对应关系在系统中未找到，请检查");
                    }
                    deptExec = deptMapper.selectOne(Wrappers.<Dept>query().eq("hrp_code", execMap.getHrpCode()));
                    if (deptExec == null) {
                        throw new BusinessException("执行科室【" + hisBill.getDeptCodeOp() + "】在系统中未找到，请检查");
                    }
                } else {
                    //消耗科室
                    deptUse = deptMapper.selectOne(Wrappers.<Dept>query().eq("his_code", hisBill.getDeptCodePatient()));
                    if (deptUse == null) {
                        throw new BusinessException("消耗科室【" + hisBill.getDeptCodePatient() + "】在系统中未找到，请检查");
                    }

                    //执行科室
                    deptExec = deptMapper.selectOne(Wrappers.<Dept>query().eq("his_code", hisBill.getDeptCodeOp()));
                    if (deptExec == null) {
                        throw new BusinessException("执行科室【" + hisBill.getDeptCodeOp() + "】在系统中未找到，请检查");
                    }

                }

                //消耗科室==执行科室
                if (ParameterUtils.isHisBillDept()) {
                    deptUse = deptExec;
                }
                if (StringUtils.isBlank(deptUse.getWarehouseId()))
                    throw new BusinessException("消耗科室【" + deptUse.getName() + "】未设置有效仓库，请联系运营人员进行设置");
                if (StringUtils.isBlank(deptUse.getWarehouseName()))
                    throw new BusinessException("消耗科室【" + deptUse.getName() + "】未设置有效仓库，请联系运营人员进行设置");
                //消耗仓库为实物所对应的科室仓库
                User user = userService.findByWorkNo(UtilCommon.getStr(hisBill.getExecUser(), "his"));
                String userName = "his";
                if (user != null) userName = user.getName();


                Stock stockWarehouse = stockService.getStockByUniqueCode(hisBill.getSn());
                if (stockWarehouse == null) {
                    throw new BusinessException("【" + hisBill.getSn() + "】在系统中未找到，请检查");
                }
                if (stockWarehouse.getSkuQty() > 0 && flagUseRedType == 1) {
                    continue;
                }
                if (stockWarehouse.getSkuQty() == 0 && flagUseRedType == 0) {
                    continue;
                }

                //主表
                OprtUse oprtUse = new OprtUse();
                oprtUse.setBusType("HIS").setFlagUseRedType(flagUseRedType)
                        .setOprtDate(oprt.getDate()).setOprtCode(hisBill.getOprtCode()).setBusDate(hisBill.getBillDate())
                        .setOprtId(oprt.getId()).setOprtName(oprt.getName()).setPatientId(patient.getId())
                        .setInpatientNo(patient.getInpatientNo()).setOutpatientNo("")
                        .setPatientNo(patient.getNo()).setPatientAge(patient.getAge()).setPatientName(patient.getName())
                        .setPatientId(patient.getId())
                        .setBedNo(patient.getBedNo()).setDocNameSug(oprt.getDoctorNameSug())
                        .setDocNameApply(oprt.getDoctorNameApply()).setDeptId(deptUse.getId())
                        .setExecDeptId(deptExec.getId()).setExecDeptName(deptExec.getName())
                        .setDeptName(deptUse.getName()).setRefKey(hisBill.getHisKey())
                        .setAmount(0d).setRemark("定时任务后补产生")
                        .setWarehouseId(stockWarehouse.getWarehouseId()).setWarehouseName(stockWarehouse.getWarehouseName())
                        .setFlowStatus("end").setFlowModifier(userName)
                        .setFlowModified(DateUtils.dateToLocalDateTime(hisBill.getBillDate()))
                        .setCreator(userName)
                ;
                // 保存主表
                this.saveOrUpdate(oprtUse);

                MatrHisDTO matrHisDTO = new MatrHisDTO();
                matrHisDTO.setHisCode(hisBill.getMatrCodeHis());
                matrHisDTO.setHisPrice(hisBill.getPrice());
                //保存明细
                List<String> stockIds = Lists.newArrayListWithCapacity(1);
                stockIds.add(stockWarehouse.getId());
                oprtUseItemService.saveByStockIds(stockIds, oprtUse.getId());

                //生成出库单
                List<WorkOrder> wos = convertUseToOrders(oprtUse, Arrays.asList(stockWarehouse));

                // 修改记账单信息 手术单号
                // 修改记账单信息 手术单号
                //       过账
                List<String> workIds = wos.stream().map(WorkOrder::getId).collect(Collectors.toList());
                workOrderService.postBatch(workIds);
                   /*暂时注释掉，待后期改造wyt20211208  // 修改记账单，手术，病人字段
                    billService.update(Wrappers.<Bill>update()
                        .in("ref_id", workIds)
                            .set(StringUtils.isNotBlank(oprtUse.getOprtId()), "oprt_id", oprtUse.getOprtId())
                            .set(StringUtils.isNotBlank(oprtUse.getOprtCode()), "oprt_code", oprtUse.getOprtCode())
                            .set(StringUtils.isNotBlank(oprtUse.getOprtName()), "oprt_name", oprtUse.getOprtName())
                            .set(StringUtils.isNotBlank(oprtUse.getPatientId()), "patient_id", oprtUse.getPatientId())
                            .set(StringUtils.isNotBlank(oprtUse.getPatientNo()), "patient_no", oprtUse.getPatientNo())
                            .set(StringUtils.isNotBlank(oprtUse.getPatientName()), "patient_name", oprtUse.getPatientName())
                            .set("dept_id", deptUse.getId())
                            .set("dept_name", deptUse.getName())
                            .set("exec_dept_id", deptExec.getId())
                            .set("exec_dept_name", deptExec.getName())
                    );

                //        修改HIS相关信息
                billMapper.updateItemHis(oprtUse.getId());*/
                if (flagUseRedType == 1) {
                    List<Stock> stocksPrice = new ArrayList<>();
                    stocksPrice.add(stockWarehouse);
                    List<Matr> matrList = matrMapper.selectList(Wrappers.<Matr>query().in("id", stockWarehouse.getMatrId()));

                    //价格变动的库存列表
                    List<Stock> stockPriceChangeList = stocksPrice.stream().filter(stock -> matrList.stream()
                            .filter(matr -> matr.getId().equals(stock.getMatrId())
                                    && matr.getSupplierId().equals(stock.getSupplierId())
                                    && matr.getFlagOmoc().equals(stock.getFlagOmoc())
                                    && !matr.getSkuPrice().equals(stock.getSkuPrice())).count() > 0)
                            .collect(Collectors.toList());
                    if (!stockPriceChangeList.isEmpty()) {
                        for (Stock stockOld : stockPriceChangeList) {
                            Matr matrNew = matrMapper.selectById(stockOld.getMatrId());
                            AdjustStockDTO adjustStockDTO = new AdjustStockDTO();
                            BeanUtils.copyProperties(stockOld, adjustStockDTO);
                            CommonService.priceChange(matrNew, adjustStockDTO, "MANUAL-BILL-CANCEL", "HIS退费后，一物一码价格变动", true, true, GlobalConsts.adjustTypeHIS);
                        }
                    }
                }
                hisBill.setFlagComparison(true);
                hisBillService.updateCascadeById(hisBill);
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            log.setLog(LogType.error, e != null ? e.getMessage() : "未知");
            restResult.setMsg("操作失败," + e.getMessage());
            restResult.setCode(ErrorCode.COMMON_ERROR);
            restResult.setSuccess(false);
        } finally {
            logService.save(log);
            return restResult;
        }
    }

    /**
     * @description: 高值锁定
     * @author: Tai
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void lockBatchOnly(HisHighLock param,boolean isReturn) {
        HisHighLockDtl dtlTop = param.getDataArr().get(0);
        Dept dept = deptMapper.selectOne(Wrappers.<Dept>query().eq("his_code", dtlTop.getDeptCodeLock()));
        BusinessException.throwValidFailIf(dept == null, "未找到相关科室，his编码[%s]",dtlTop.getDeptCodeLock());
        BusinessException.throwValidFailIf(StringUtils.isBlank(dept.getWarehouseId()), "未配置科室仓库，科室[%s]",dept.getWarehouseName());

        List<String> ukList = param.getDataArr().stream().map(HisHighLockDtl::getUniqueCode).collect(Collectors.toList());
        List<Stock> stockList;
        if (isReturn) { // 退费
            List<OprtUseItem> oprtUseItemList = oprtUseItemMapper.getRedItemsBySn(dept.getId(), ukList);
            List<String> ukListAll = oprtUseItemList.stream().map(OprtUseItem::getSn).collect(Collectors.toList());
            ukListAll.addAll(oprtUseItemList.stream().filter(item -> StringUtils.isNotBlank(item.getSn())).map(OprtUseItem::getSn).collect(Collectors.toList()));
            List<String> ukListLess = ukList.stream().filter( uk -> !ukListAll.contains(uk)).collect(Collectors.toList());
            if (ObjectUtil.length(ukListLess) > 0) {
                throw new ValidException("标签码%s未找到相关收费明细", ukListLess.get(0));
            }
            Stock stockOne;
            stockList = new ArrayList<>();
            for(OprtUseItem item : oprtUseItemList){
                stockOne = new Stock();
                BeanUtils.copyProperties(item, stockOne);
                stockOne.setId(item.getStockId());
                stockList.add(stockOne);
            }
        }else {//计费
            stockList = stockService.list(new QueryWrapper<Stock>().in("sn", ukList).or().in("rfid", ukList));
            List<String> ukListAll = stockList.stream().map(Stock::getSn).collect(Collectors.toList());
            ukListAll.addAll(stockList.stream().filter(item -> StringUtils.isNotBlank(item.getSn())).map(Stock::getSn).collect(Collectors.toList()));
            List<String> ukListLess = ukList.stream().filter( uk -> !ukListAll.contains(uk)).collect(Collectors.toList());
            if (ObjectUtil.length(ukListLess) > 0) {
                throw new ValidException("标签码[%s]未找到相关库存", ukListLess.get(0));
            }

            Date date = new Date();
            stockList.stream().filter(stock -> DateUtils.compareDate(stock.getExpDate(), date)).findFirst().ifPresent(stock -> {
                throw new ValidException("标签码[%s]效期[%s]已过期", stock.getSn(), DateUtils.format(stock.getExpDate()));
            });

            stockList.stream().filter(stock -> !stock.getFlagOmoc()).findAny().ifPresent(stock -> {
                throw new ValidException(stock.getSn() + "唯一码不是标签管理耗材，不可操作");
            });

            stockList.stream().filter(stock -> stock.getPackageQty() == 0).findAny().ifPresent(stock -> {
                throw new ValidException(stock.getSn() + "库存为0,不可操作");
            });
        }

        // 锁库存
        List<String> stockIds = stockList.stream().map(Stock::getId).collect(Collectors.toList());
        List<StockLock> locks = stockLockService.list(Wrappers.<StockLock>query().in("stock_id", stockIds));
        if (locks != null && locks.size() > 0){
            BusinessException.throwValidFail("唯一码无法使用，已被锁定: [%s]",locks.get(0).getLockComment());
        }

        //4批量加锁
        List<StockLock> stockLockSave = new ArrayList<StockLock>();
        Date now = DateUtils.now();
        StockLock stockLock = null;
        String busType = isReturn ? "退费" : "计费";
        for(Stock stock : stockList) {
            stockLock = new StockLock();
            stockLock.setWarehouseId(dept.getWarehouseId());
            stockLock.setBusType(LockBusType.HIS_QUERY.name());
            stockLock.setBusKeyValue(dtlTop.getRefKey());
            stockLock.setMatrId(stock.getMatrId());
            stockLock.setStockId(stock.getId());//锁定的是对应库存的id
            stockLock.setUc(stock.getSn());//唯一码类型
            stockLock.setUcType(UniqueCodeType.SN.name());
            stockLock.setQty(stock.getSkuQty());
            stockLock.setLockTime(now);
            stockLock.setLockComment(StrUtil.format("HIS{}查询锁定,单号:{},时间:{}",busType,dtlTop.getRefKey(),DateUtils.format(now,DateUtils.YYYYMMDDHHMMSS_PATTER2)));
            stockLock.setRefBusType(LockBusType.HIS_QUERY.name());
            stockLockSave.add(stockLock);
        }
        stockLockService.saveBatch(stockLockSave);
    }

    /**
     * @description: 高值解锁
     * @author: Tai
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unlockBatchOnly(HisHighUnlock param, boolean isReturn) {
        HisHighUnlockDtl dtlTop = param.getDataArr().get(0);

        List<String> ukList = param.getDataArr().stream().map(HisHighUnlockDtl::getUniqueCode).collect(Collectors.toList());
        List<Stock> stockList;
        if (isReturn) { // 退费
            List<OprtUseItem> oprtUseItemList = oprtUseItemMapper.getRedItemsBySn(null, ukList);
            List<String> ukListAll = oprtUseItemList.stream().map(OprtUseItem::getSn).collect(Collectors.toList());
            ukListAll.addAll(oprtUseItemList.stream().filter(item -> StringUtils.isNotBlank(item.getSn())).map(OprtUseItem::getSn).collect(Collectors.toList()));
            List<String> ukListLess = ukList.stream().filter( uk -> !ukListAll.contains(uk)).collect(Collectors.toList());
            // 因为查询的时候没有校验锁定，有可能出现查询的是已锁定的，这个地方找不到消耗记录，就返回
            if (ObjectUtil.length(ukListLess) > 0) {
                return;
                //throw new ValidException("标签码[%s]未找到相关库存", ukListLess.get(0));
            }
            Stock stockOne;
            stockList = new ArrayList<>();
            for(OprtUseItem item : oprtUseItemList){
                stockOne = new Stock();
                BeanUtils.copyProperties(item, stockOne);
                stockOne.setId(item.getStockId());
                stockList.add(stockOne);
            }
        }else {//计费
            stockList = stockService.list(new QueryWrapper<Stock>().in("sn", ukList).or().in("rfid", ukList));
            List<String> ukListAll = stockList.stream().map(Stock::getSn).collect(Collectors.toList());
            ukListAll.addAll(stockList.stream().filter(item -> StringUtils.isNotBlank(item.getSn())).map(Stock::getSn).collect(Collectors.toList()));
            List<String> ukListLess = ukList.stream().filter( uk -> !ukListAll.contains(uk)).collect(Collectors.toList());
            // 因为查询的时候没有校验锁定，有可能出现查询的是已锁定的，这个地方找不到消耗记录，就返回
            if (ObjectUtil.length(ukListLess) > 0) {
                throw new ValidException("标签码[%s]未找到相关库存", ukListLess.get(0));
            }
        }

        // 锁库存
        List<String> stockIds = stockList.stream().map(Stock::getId).collect(Collectors.toList());
        List<StockLock> locks = stockLockService.list(Wrappers.<StockLock>query().in("stock_id", stockIds));
        if (ObjectUtil.length(locks) != param.getDataArr().size()){
            List<String> lockStockIdAll = locks.stream().map(StockLock::getStockId).collect(Collectors.toList());
            List<String> ukListLess = stockList.stream().filter( item -> !lockStockIdAll.contains(item.getId())).map(Stock::getSn).collect(Collectors.toList());
            throw new ValidException("标签码[%s]未找到相关锁定信息", ukListLess.get(0));
        }

        List<StockLock> locksErr = locks.stream().filter(item -> !item.getBusKeyValue().equals(dtlTop.getRefKey())).collect(Collectors.toList());
        if (ObjectUtil.length(locksErr) > 0) {
            BusinessException.throwValidFail("已锁定单据[%s]与传入单据[%s]不一致",locksErr.get(0).getBusKeyValue(),dtlTop.getRefKey());
        }

        //4解锁日志
        Date now = DateUtils.now();
        List<StockLockLog> stockLockLogSave = new ArrayList<StockLockLog>();
        StockLockLog stockLockLog =null;
        for(StockLock stockLock : locks) {
            stockLockLog = new StockLockLog();
            BeanUtils.copyProperties(stockLock, stockLockLog);
            stockLockLog.setUnlockTime(now);
            stockLockLog.setId(null);
            stockLockLogSave.add(stockLockLog);
        }
        stockLockLogService.saveBatch(stockLockLogSave);
        stockLockService.removeCascadeByIds(locks.stream().map(StockLock::getId).collect(Collectors.toList()));
    }

    /**
     * @Description： HIS计费或者退费
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void hisSaveOprtUseBatchV2(HisHighBillBatch param, boolean isReturn, boolean isUnlockQueryHis) {
        if (isUnlockQueryHis) {
            HisHighUnlock unlockBatch = new HisHighUnlock();
            List<HisHighUnlockDtl> unlockDtlList = new ArrayList<>();
            HisHighUnlockDtl unlockDtl;
            for(HisHighBillBatchDtl billDtl : param.getDataArr()) {
                unlockDtl = new HisHighUnlockDtl();
                BeanUtils.copyProperties(billDtl, unlockDtl);
                unlockDtlList.add(unlockDtl);
            }
            unlockBatch.setDataArr(unlockDtlList);

            this.unlockBatchOnly(unlockBatch, isReturn);
        }
        List<HisOprtUseBatch> hisOprtUseBatches = new ArrayList<>();
        HisOprtUseBatch oprtUseBatchDtl;
        for(HisHighBillBatchDtl dtl : param.getDataArr()) {
            oprtUseBatchDtl = new HisOprtUseBatch();
            BeanUtils.copyProperties(dtl, oprtUseBatchDtl);
            oprtUseBatchDtl.setBillFlag(1);
            oprtUseBatchDtl.setRefkey(dtl.getRefKey());
            if (dtl.getBillFlag().equals("-1")) {
                oprtUseBatchDtl.setBillFlag(-1);
            }
            hisOprtUseBatches.add(oprtUseBatchDtl);
        }
        this.hisSaveOprtUseBatch(hisOprtUseBatches);
    }

}
